package IC.AST;

public class PrintVisitor extends Visitor
{	
	private int _spaceing = 0;
	
	private void PrintSpace()
	{
		String space = new String();
		for (int l = 0; l < _spaceing; l++)
			space += " ";
		
		System.out.print(space);
	}
	
	//you are welcome to debug this on the example.ic -Llibic.sig -print-ast -dump-symtab
	private void PrintTitle(ASTNode node, String title)
	{	
		PrintSpace();
		System.out.format("%s. Type:%s Sym Table:%s\n", 
				node.GetInterval().toString(), node.GetType(), node.GetSymbolTable().GetShortName());
		PrintSpace();
		System.out.println(title);
	}
	
	private void PrintSonName(String name)
	{
		PrintSpace();
		System.out.println(name);
	}
	
	public Object Visit(ArrayLocation node) 
	{
		PrintTitle(node, "Array Location");
		PrintSonName("Array");
		_spaceing++;
		node.GetArray().Visit(this);
		_spaceing--;
		PrintSonName("Index");
		_spaceing++;
		node.GetIndex().Visit(this);
		_spaceing--;
		return null;
	}
	
	public Object Visit(AssignStatement node)
	{
		PrintTitle(node, "Assignment Statement");
		PrintSonName("Location");
		_spaceing++;
		node.GetWhereTo().Visit(this);
		_spaceing--;
		PrintSonName("Statement");
		_spaceing++;
		node.GetWhat().Visit(this);
		_spaceing--;
		return null;
	}
	
	public Object Visit(BasicType node)
	{
		PrintTitle(node, 
				"Basic type of " + 
				node.GetBasicTypetype().toString() + " with dimension=" + node.GetDimension() + " .");
		return null;
	}
	
	public Object Visit(BinaryOperationExpression node)
	{
		PrintTitle(node, "Binary Operation Expression of type:" + node.GetOperation().toString());
		PrintSonName("First expression:");
		_spaceing++;
		node.GetFirstExp().Visit(this);
		_spaceing--;
		PrintSonName("Second expression:");
		_spaceing++;
		node.GetSecondExp().Visit(this);
		_spaceing--;
		return null;
	}
	
	public Object Visit(BooleanLiteral node)
	{
		PrintTitle(node, "Boolean Literal of value:" + node.GetVaule());
		return null;
	}
	
	public Object Visit(BreakStatement node)
	{
		PrintTitle(node, "Break Statement");
		return null;
	}
	
	public Object Visit(ClassDeclaration node)
	{
		PrintTitle(node
				, "Class Declaration, id=" + node.GetID() + 
					((node.GetSuperClassID() == null) ? 
							"." 
					:
							" extending class=" + node.GetSuperClassID() + "."));
		
		int count = 1;
		for (ClassField feild : node.GetFields())
		{
			PrintSonName("Feild #" + count++ + ":");
			_spaceing++;
			feild.Visit(this);
			_spaceing--;
		}
		
		count = 1;
		for (Method method : node.GetMethods())
		{
			PrintSonName("Method #" + count++ + ":");
			_spaceing++;
			method.Visit(this);
			_spaceing--;
		}
		
		return null;
	}
	
	public Object Visit(ClassField node)
	{
		PrintTitle(node, "Class Feild with id=" + node.GetID() + ".");
		PrintSonName("Type:");
		_spaceing++;
		node.GetASTType().Visit(this);
		_spaceing--;
		return null;
	}
	
	public Object Visit(ClassType node)
	{
		PrintTitle(node, "Class type with classname=" + node.GetClassName() + " with dimension=" + node.GetDimension() + ".");
		return null;
	}
	
	public Object Visit(ContinueStatement node)
	{
		PrintTitle(node, "Continue statement.");
		return null;
	}
	
	public Object Visit(DeclorationStatement node)
	{
		PrintTitle(node, "Varible decloration statement id=" + node.GetID());
		PrintSonName("Type:");
		_spaceing++;
		node.GetASTType().Visit(this);
		_spaceing--;
		if (node.GetExpression() != null)
		{
			PrintSonName("Decloration assigment expression");
			_spaceing++;
			node.GetExpression().Visit(this);
			_spaceing--;
		}
		else
			PrintSonName("No decloration assigment expression");
		
		return null;
	}
	
	public Object Visit(DotLocation node)
	{
		PrintTitle(node, "Dot location with rightID=" + node.GetRightID() + " .");
		PrintSonName("Left expression:");
		_spaceing++;
		node.GetLeftExpression().Visit(this);
		_spaceing--;
		return null;
	}
	
	public Object Visit(Formal node)
	{
		PrintTitle(node, "Formal (Parameter) with id=" + node.GetID() + " .");
		PrintSonName("Type:");
		_spaceing++;
		node.GetASTType().Visit(this);
		_spaceing--;
		return null;	
	}
	
	public Object Visit(FunctionCall node)
	{
		PrintTitle(node, "Function call, with name=" + node.GetFunctionName() + " .");
		
		int count = 1;
		if (node.GetParams().size() != 0)
			for (Expression expression : node.GetParams())
			{
				PrintSonName("Parameter expression #" + count++ + ".");
				_spaceing++;
				expression.Visit(this);
				_spaceing--;
			}
		else
			PrintSonName("No parameters for the function");
		return null;
	}
	
	public Object Visit(FunctionCallExpression node)
	{
		PrintTitle(node, "Function Class Expression.");
		PrintSonName("Function call:");
		_spaceing++;
		node.GetFunctionCall().Visit(this);
		_spaceing--;
		return null;	
	}
	
	public Object Visit(FunctionCallStatement node)
	{
		PrintTitle(node, "Function call statement.");
		PrintSonName("Function call:");
		_spaceing++;
		node.GetFunctionCall().Visit(this);
		_spaceing--;
		return null;
	}
	
	public Object Visit(IfStatement node)
	{
		PrintTitle(node, "If statement.");
		PrintSonName("If expression:");
		_spaceing++;
		node.GetIfExpression().Visit(this);
		_spaceing--;
		PrintSonName("If statement:");
		_spaceing++;
		node.GetFirstPart().Visit(this);
		_spaceing--;
		if (node.GetSecondPart() != null)
		{
			PrintSonName("Else statment:");
			_spaceing++;
			node.GetSecondPart().Visit(this);
			_spaceing--;
		}
		else
			PrintSonName("There is no else statement.");
		
		return null;
	}
	
	public Object Visit(IntegerLiteral node)
	{
		PrintTitle(node, "Integer Literal with value=" + node.GetVaule() + " .");
		return null;
	}
	
	public Object Visit(LengthExpression node)
	{
		PrintTitle(node, "Length expression.");
		PrintSonName("Expression:");
		_spaceing++;
		node.GetExpression().Visit(this);
		_spaceing--;
		return null;
	}
	
	public Object Visit(LiteralExpression node)
	{
		PrintTitle(node, "Literal expression.");
		PrintSonName("Literal:");
		_spaceing++;
		node.GetLiteral().Visit(this);
		_spaceing--;
		return null;
	}
	
	public Object Visit(Method node)
	{
		PrintTitle(node, 
				"Method with id=" + node.GetID() + 
				((node.GetReturnType() == null) ? " with return type void" : "") + " static=" + node.IsStatic() + " .");
		
		
		if (node.GetReturnType() != null)
		{	
			_spaceing++;
			PrintSonName("Return type:");
			node.GetReturnType().Visit(this);
			_spaceing--;
		}
		
		if (node.GetFormals() != null)
		{
			int count = 1;
			for (Formal formal : node.GetFormals())
			{
				PrintSonName("Parameter #" + count++ + ":");
				_spaceing++;
				formal.Visit(this);
				_spaceing--;
			}	
		}
		else
			PrintSonName("No parameters.");
		
		PrintSonName("Scoped Statements:");
		node.GetScope().Visit(this);
		
		return null;
	}
	
	public Object Visit(NewArrayExpression node)
	{
		PrintTitle(node, "New array expression.");
		PrintSonName("Type:");
		_spaceing++;
		node.GetASTType().Visit(this);
		_spaceing--;
		PrintSonName("Size Expression:");
		_spaceing++;
		node.GetSizeExpression().Visit(this);
		_spaceing--;
		return null;
	}
	
	public Object Visit(NewClassExpression node)
	{
		PrintTitle(node, "New class expression id=" + node.GetClassID());
		return null;
	}
	
	public Object Visit(NullLiteral node)
	{
		PrintTitle(node, "Null literal.");
		return null;	
	}
	
	public Object Visit(Program node)
	{
		PrintTitle(node, "Program node.");
		if (node.GetListOfClasses() != null)
		{
			int count = 1;
			for (ClassDeclaration classDecel : node.GetListOfClasses())
			{
				PrintSonName("Class declaration #" + count++ + ":");
				_spaceing++;
				classDecel.Visit(this);
				_spaceing--;		
			}
		}
		else
			PrintSonName("There where no class declarations.");
		
		return null;
	}
	
	public Object Visit(QuoteLiteral node)
	{
		PrintTitle(node, "Quote literal with value=\"" + node.GetValue() + "\" .");
		return null;
	}
	
	public Object Visit(ReturnStatement node)
	{
		PrintTitle(node, "Return statement.");
		if (node.GetReturnValue() != null)
		{
			PrintSonName("Return value expression:");
			_spaceing++;
			node.GetReturnValue().Visit(this);
			_spaceing--;
		}
		else
			PrintSonName("Return expression with no value.");
		return null;
	}
	
	public Object Visit(ScopeStatement node)
	{
		PrintTitle(node, "Scope statement.");
		if (node.GetListOfStatements() != null)
		{
			int count = 1;
			for (Statement statement : node.GetListOfStatements())
			{
				PrintSonName("Statement #" + count++ + ":");
				_spaceing++;
				statement.Visit(this);
				_spaceing--;
			}
		}
		else
			PrintSonName("No statements in this scope block.");
		
		return null;
	}
	
	public Object Visit(SimpleLocation node)
	{
		PrintTitle(node, "Simple location with id=" + node.GetID() + ".");
		return null;
	}
	
	public Object Visit(StaticFunctionCall node)
	{
		PrintTitle(node, "Static function call, function from class=" + node.GetClassName() + ".");
		PrintSonName("Function body:");
		_spaceing++;
		Visit((FunctionCall)node);
		_spaceing--;
		return null;
	}
	
	public Object Visit(ThisExpression node)
	{
		PrintTitle(node, "This expression.");
		return null;
	}
	
	public Object Visit(UnaryOperationExpression node)
	{
		PrintTitle(node, "Unary operation expression with operation=" + node.GetOperation().toString() + " .");
		PrintSonName("Expression:");
		_spaceing++;
		node.GetExpression().Visit(this);
		_spaceing--;
		return null;
	}
	
	public Object Visit(VirtualFunctionCall node)
	{
		PrintTitle(node, "Virtual (none static) function call.");
		PrintSonName("Class expression:");
		_spaceing++;
		node.GetInvokedExpression().Visit(this);
		_spaceing--;
		PrintSonName("Function body:");
		_spaceing++;
		Visit((FunctionCall)node);
		_spaceing--;
		return null;	
	}
	
	public Object Visit(WhileStatement node)
	{
		PrintTitle(node, "While statement.");
		PrintSonName("While expression:");
		_spaceing++;
		node.GetExpression().Visit(this);
		_spaceing--;
		PrintSonName("While statement(s):");
		_spaceing++;
		node.GetSatement().Visit(this);
		_spaceing--;
		return null;
	}
	

	public Object Visit(Library node)
	{
		PrintTitle(node, "Library node.");
		if (node.GetListOfMethods() != null)
		{
			int count = 1;
			for (LibraryMethod methodDeclaration : node.GetListOfMethods())
			{
				PrintSonName("Method Declaration #" + count++ + ":");
				_spaceing++;
				methodDeclaration.Visit(this);
				_spaceing--;		
			}
		}
		else
			PrintSonName("There where no class declarations.");
		
		return null;
	}
	
	public Object Visit(LibraryMethod node)
	{
		PrintTitle(node, 
				"Library Method with id=" + node.GetID() + 
				((node.GetReturnType() == null) ? " with return type void" : ""));
		
		
		if (node.GetReturnType() != null)
		{	
			_spaceing++;
			PrintSonName("Return type:");
			node.GetReturnType().Visit(this);
			_spaceing--;
		}
		
		if (node.GetFormals() != null)
		{
			int count = 1;
			for (Formal formal : node.GetFormals())
			{
				PrintSonName("Parameter #" + count++ + ":");
				_spaceing++;
				formal.Visit(this);
				_spaceing--;
			}	
		}
		else
			PrintSonName("No parameters.");
		
		return null;
	}
}
